//
//  TTRTCAgoraService.swift
//  TTLive
//
//  Created by Toj on 2/1/21.
//

import Foundation

// MARK: - Init
open class TTRTCAgoraService: TTRTCService {
    
    private override init() { }
    public static let shared = TTRTCAgoraService()
    
    private var agoraKit: AgoraRtcEngineKit?
    
    public func setupAgoraParameter(appID: String, token: String) {
        self.appID = appID
        self.token = token
    }
}

// MARK: - TTRTCProtocol
extension TTRTCAgoraService: TTRTCProtocol {
    public func switchCamera() {
        
    }
    
    
    public var arcType: Int {
        return 0
    }
    
    public func joinLiveRoom(userID: TTUInt, roomID: String, local view: TTView) {
        self.userID = userID
        self.roomID = roomID
        self.localView = view
        setupLiveServerEngine()
        joinChannel()
    }
    
    // 拉取指定人视频流
    public func pullRemoteVideo(uid: TTUInt, remote view: TTView) {
        setupRemoteVideo(uid: uid, view: view)
        remoteDidJoinedBlock?(uid)
    }
    
    public func switchStream(uid new: TTUInt, remote view: TTView) {
        setupRemoteVideo(uid: new, view: view)
    }
    
    private func joinLiveRoom() {
        localWillJoinBlock?(userID)
        
        agoraKit?.joinChannel(byToken: token, channelId: roomID, info: nil, uid: userID, joinSuccess: { [weak self] (_, uid, _) in
            self?.localDidJoinedBlock?(uid)
        })
    }
    
    // 退出房间
    public func quitLiveRoom(complete quitBlock: TTRTCQuitLiveRoom?) {
        agoraKit?.leaveChannel({ [weak self] (stat) in
            self?.destroyAgoraKit()
            quitBlock?()
        })
    }
    
    // 切换视频分辨率(大流/小流)
    public func switchRemoteVideoStream(uid: TTUInt, type: TTVideoStreamType) {
        let streamType = AgoraVideoStreamType(rawValue: type.rawValue) ?? .low
        agoraKit?.setRemoteVideoStream(uid, type: streamType)
    }
    
    // 本地视频采集 (打开/ 关闭)
    public func localVideo(enabled: Bool) {
        agoraKit?.enableLocalVideo(enabled)
    }
    
    // 本地视频推流 (打开/ 关闭)
    public func pushLocalVideoStream(muted: Bool) {
        agoraKit?.muteLocalVideoStream(muted)
    }
  
    // 本地音频推流 (打开/ 关闭)
    public func pushLocalAudioStream(muted: Bool) {
        agoraKit?.muteLocalAudioStream(muted)
    }
   
    // 远端视频拉流个人 (打开/ 关闭)
    public func pullRemoteVideoStream(uid: TTUInt, muted: Bool) {
        agoraKit?.muteRemoteVideoStream(uid, mute: muted)
    }
    
    // 远端音频拉流个人 (打开/ 关闭)
    public func pullRemoteAudioStream(uid: TTUInt, muted: Bool) {
        agoraKit?.muteRemoteAudioStream(uid, mute: muted)
    }
    
    // 远端视频拉流全部 (打开/ 关闭)
    public func pullRemoteVideoStreamAll(muted: Bool) {
        agoraKit?.muteAllRemoteVideoStreams(muted)
    }
    
    // 远端音频拉流全部 (打开/ 关闭)
    public func pullRemoteAudioStreamAll(muted: Bool) {
        agoraKit?.muteAllRemoteAudioStreams(muted)
    }
    
    // 设置美颜效果选项
    public func beautyEffect(enable: Bool) { }
    
    // // iPhone
    // #if TARGET_OS_IPHONE
    // // 切换前置摄像头, 仅适用于 iOS 平台，不适用于 macOS
    // - (void)switchCamera {
    //     [VIPWrite writeLogWithFormat:@"%s", __func__];
    //
    //     [self.agoraKit switchCamera];
    // }
    // #endif
    
    
    // 屏幕共享
    #if canImport(Cocoa)
    // 全屏
    public func sharedFullScreen() -> Int32 {
        let screen = TTRTCAgoraConfig.ScreenCapture.self
        
        return agoraKit?.startScreenCapture(byDisplayId: 0, rectangle: .zero, parameters: screen.fullParameters) ?? -1
    }
    
    // 指定窗口
    public func sharedScreenWindowId(windowId: TTUInt, size: CGSize = .zero) -> Int32 {
        let screen = TTRTCAgoraConfig.ScreenCapture.self
        
        return agoraKit?.startScreenCapture(byWindowId: windowId, rectangle: screen.rect, parameters: screen.parameters(dimensions: size)) ?? -1
    }
    
    // 指定屏幕
    public func sharedScreenDisplayId(displayId: TTUInt, size: CGSize = .zero) -> Int32 {
        let screen = TTRTCAgoraConfig.ScreenCapture.self
        
        return agoraKit?.startScreenCapture(byDisplayId: displayId, rectangle: screen.rect, parameters: screen.parameters(dimensions: size)) ?? -1
    }
    
    // 关闭屏幕共享
    public func stopScreenCapture() -> Int32 {
        return agoraKit?.stopScreenCapture() ?? -1
    }
    #endif
    
    public func destroyRTC() {
        destroyAgoraKit()
        destroyServer()
    }
    
    public func sdkVersion() -> String {
        return AgoraRtcEngineKit.getSdkVersion()
    }
}

// MARK: - AgoraRtcEngineDelegate
extension TTRTCAgoraService: AgoraRtcEngineDelegate {
    /** 本地进入频道回调,
     * joinSuccessBlock 优先级高于 didJoinChannel,
     * 2个同时存在时, didJoinChannel 会被忽略. 需要有 didJoinChannel 回调时, 请将 joinSuccessBlock 设置为 nil.
     public func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) { }
     */
    
    // 本地视频第一帧显示时, 触发此回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, firstLocalVideoFrameWith size: CGSize, elapsed: Int) {
        localFirstVideoDecodedBlock?(userID)
    }
    
    // 有时候由于网络原因, 客户端可能会和服务器失去连接, SDK 会进行自动重连, 自动重连成功后触发此回调方法.
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didRejoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
        localReJoinedBlock?(uid)
    }
    
    // 远端进入回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
        remoteDidJoinedOfUid(uid)
    }
    
    // 远端首帧视频显示回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoDecodedOfUid uid: UInt, size: CGSize, elapsed: Int) {
        remoteFirstVideoDecodedBlock?(uid)
    }
    
    // 远端用户停止/重新发送视频回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didVideoMuted muted: Bool, byUid uid: UInt) {
        didVideoMutedBlock?(muted, uid)
    }
    
    // 静音回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didAudioMuted muted: Bool, byUid uid: UInt) {
        didAudioMutedBlock?(muted, uid)
    }
    
    // 频道内网络质量（上下行）
    public func rtcEngine(_ engine: AgoraRtcEngineKit, networkQuality uid: UInt, txQuality: AgoraNetworkQuality, rxQuality: AgoraNetworkQuality) {
        guard videoNetworkQualityBlock != nil else { return }
        
        // 取最低的质量
        let quality = txQuality.rawValue > rxQuality.rawValue ? rxQuality : txQuality
        let level = quality.level
        let aUserID = uid == 0 ? userID : uid
        
        videoNetworkQualityBlock?(aUserID, level);
    }
    
    // 音量提示回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) {
        guard audioVolumeIndicationBlock != nil else { return }
        
        speakers.forEach { (volumeInfo) in
            var uid = volumeInfo.uid
            if  uid == 0 { uid = userID }
            audioVolumeIndicationBlock?(uid, volumeInfo.volume)
        }
    }
    
    // 用户离线
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
        remoteDidOfflineBlock?(uid)
    }
    
    // Token 过期已经过期回调
    public func rtcEngineRequestToken(_ engine: AgoraRtcEngineKit) {
        
        tokenDidTimeoutBlock?()
    }
    
    // 发生错误回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) {
        
        didOccurErrorBlock?(errorCode.rawValue)
    }
    
    // 接收对方数据流消息错误的回调
    public func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurStreamMessageErrorFromUid uid: UInt, streamId: Int, error: Int, missed: Int, cached: Int) {
        
        didOccurStreamMessageErrorBlock?(uid, error)
    }
}

// MARK: - Private
extension TTRTCAgoraService {
    
    // 进入频道
    private func joinChannel() {
        joinLiveRoom()
    }
    
    private func remoteDidJoinedOfUid(_ uid: TTUInt) {
        remoteDidJoined(uid: uid) { [weak self] (remoteView) in
            self?.pullRemoteVideo(uid: uid, remote: remoteView)
        }
    }
    
    // 创建 AgoraRtcVideoCanvas 视频画布对象
    private func setupVideoCanvas(uid: TTUInt, view: TTView, mode: AgoraVideoRenderMode = TTRTCAgoraConfig.Video.renderMode) -> AgoraRtcVideoCanvas {
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = view
        videoCanvas.renderMode = mode
        return videoCanvas
    }
    
    private func setupRemoteVideo(uid: TTUInt, view: TTView) {
        let videoCanvas = setupVideoCanvas(uid: uid, view: view)
        agoraKit?.setupRemoteVideo(videoCanvas)
    }
    
    private func destroyAgoraKit() {
        // 关闭视频模块
        agoraKit?.disableVideo()
        // 关闭本地视频预览
        agoraKit?.stopPreview()
        // 释放本地视图
        agoraKit?.setupLocalVideo(nil)
        // 断开引用 AgoraRtcEngineKit 实例
        agoraKit = nil
        localView = nil
        // 销毁 AgoraRtcEngineKit 实例
        AgoraRtcEngineKit.destroy()
    }
}

// MARK: - Setup
private extension TTRTCAgoraService {
    
    func setupLiveServerEngine() {
        // 实例化声网
        setupAgoraKit(appID: appID)
        
        // 设置日志
        setupAgoraLog()
        
        // 设置本地视频属性
        setupAgoraVideoConfig()
        
        // 设置本地音频属性
        setupAgoraAudioConfig()
        
        // 设置本地视频画布
        setupAgoraVideoCanvas()
    }
    
    // 创建 AgoraRtcEngineKit 实例
    func setupAgoraKit(appID: String) {
        agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: appID, delegate: self)
    }
    
    // 设置本地视频属性
    func setupAgoraVideoConfig() {
        let config = TTRTCAgoraConfig.self
        let video = config.Video.self
        let parameters = config.Parameters.self
        
        // 设置分辨率, 码率, 比特位, 方向, 优化方案
        // setVideoProfile已经废弃, 建议用此方法.
        setupVideoEncoderConfiguration()
        
        // 打开视频模式
        agoraKit?.enableVideo()
        
        #if canImport(Cocoa)
        // 监控设备的改变, 仅支持 macOS 平台, 不支持 iOS 平台.
        agoraKit?.monitorDeviceChange(true)
        #endif
        
        // 开启双流
        agoraKit?.enableDualStreamMode(true)
        
        // 远端视频流(大/小)
        agoraKit?.setRemoteDefaultVideoStreamType(video.streamType)
        
        // 小流的属性设置
        agoraKit?.setParameters(parameters.low)
        
        // 设置频道模式
        agoraKit?.setChannelProfile(config.channelProfile)
        
        // 设置用户角色
        agoraKit?.setClientRole(config.clientRole)
        
        // 本地视图显示模式, 3.0废弃 setLocalRenderMode:mirrorMode:
        agoraKit?.setLocalRenderMode(video.renderMode)
        
        // 设置镜像模式, 默认auto
        // agoraKit?.setLocalVideoMirrorMode(video.mirrorMode)
    }
    
    // 设置分辨率, 码率, 比特位, 方向, 优化方案
    func setupVideoEncoderConfiguration() {
        let config = TTRTCAgoraConfig.Video.self
        
        let resolution = config.resolution
        let rate = config.rate
        let bitrate = config.bitrate
        let orientationMode = config.orientationMode
        let degradation = config.degradation
        
        let configuration = AgoraVideoEncoderConfiguration(size: resolution, frameRate: rate, bitrate: bitrate, orientationMode: orientationMode)
        configuration.degradationPreference = degradation
        agoraKit?.setVideoEncoderConfiguration(configuration)
    }
    
    // 设置SDK日志
    func setupAgoraLog() {
        let config = TTRTCAgoraConfig.self
        // 设置日志输出等级
        agoraKit?.setLogFilter(config.logFilter)
        
        // 设置日志路径
        if logFilePath.count > 0 {
            agoraKit?.setLogFile(logFilePath)
        }
    }
    
    // 初始化本地画布
    func setupAgoraVideoCanvas() {
        if let view = localView {
            let videoCanvas = setupVideoCanvas(uid: userID, view: view)
            agoraKit?.setupLocalVideo(videoCanvas)
        }
        agoraKit?.startPreview()
    }
    
    // 设置本地音频属性
    func setupAgoraAudioConfig() {
        let audio = TTRTCAgoraConfig.Audio.self
        
        // 音频采集音量
        agoraKit?.adjustRecordingSignalVolume(audio.recording)
        
        // 设置音频编码配置(音频参数和应用场景)
        agoraKit?.setAudioProfile(audio.profile, scenario: audio.scenario)
        
        // 启用音量提示
        agoraKit?.enableAudioVolumeIndication(audio.indication, smooth: audio.smooth, report_vad: audio.report_vad)
        // 播放远端音量
        agoraKit?.adjustPlaybackSignalVolume(audio.playback)
    }
}

// MARK: - AgoraNetworkQuality
extension AgoraNetworkQuality {
    
    var level: UInt { return Self.levels[self] ?? 0 }
    static let levels: [AgoraNetworkQuality: UInt] =
        [.excellent: 0, .good: 0,
         .poor     : 1,
         .bad      : 2, .vBad: 2,
         .down     : 3,
         .unknown: 4]
}
